#include "include.h"
#include "func.h"
#include "func_speaker.h"
#include "sfr.h"
#include "func_exspiflash_music.h"

#if FUNC_SPEAKER_EN
#define MAX_EXIT_CNT   30//10*60
#define MAX_PASSWORK_NUM 12
func_speaker_t f_spk;
u16 exit_cnt;
u8 wait_tts_finish=0;
#if MIC_REC_EN
AT(.text.bsp.mic)
void mic_rec_start(void)
{
    f_spk.rec_en = 1;
}

AT(.text.bsp.mic)
void mic_rec_stop(void)
{
    f_spk.rec_en = 0;
}

AT(.text.bsp.mic)
void mic_rec_init(void)
{
    rec_src.spr = SPR_16000;
    rec_src.nchannel = 1;
    rec_src.source_start = mic_rec_start;
    rec_src.source_stop  = mic_rec_stop;
    f_spk.rec_en = 0;
}
#endif // MIC_REC_EN

AT(.text.bsp.speaker)
void func_speaker_stop(void)
{
    dac_fade_out();
    dac_fade_wait();                    //等待淡出完成
    audio_path_exit(AUDIO_PATH_SPEAKER);
}

AT(.text.bsp.speaker)
void func_speaker_start(void)
{
    dac_fade_wait();                    //等待淡出完成
    audio_path_init(AUDIO_PATH_SPEAKER);
    audio_path_start(AUDIO_PATH_SPEAKER);
    dac_fade_in();
}

AT(.text.bsp.speaker)
void func_speaker_pause_play(void)
{
    if (f_spk.pause) {
        led_music_play();
        func_speaker_start();
    } else {
        led_idle();
        func_speaker_stop();
    }
    f_spk.pause ^= 1;
}

AT(.text.bsp.speaker)
void func_speaker_mp3_res_play(u32 addr, u32 len)
{
    if (len == 0) {
        return;
    }

#if MIC_REC_EN
    sfunc_record_pause();
#endif // MIC_REC_EN

    if (!f_spk.pause) {
        func_speaker_stop();
        mp3_res_play(addr, len);
        func_speaker_start();
    } else {
        mp3_res_play(addr, len);
    }

#if MIC_REC_EN
    sfunc_record_continue();
#endif // MIC_REC_EN
}

AT(.text.bsp.speaker)
void func_speaker_setvol_callback(u8 dir)
{
    if (f_spk.pause) {
        func_speaker_pause_play();
    }
}
#if 0
extern u32 dac_obuf[576];
static u16 tbl_samplerate[] = {48000,44100,38000,32000,24000,22050,16000,12000,11025,8000};
AT(.com_text.fft_dbg_str)
const char dbg_str_num[] = "%d ";
AT(.com_text.fft_dbg_str)
const char dbg_str_freqinfo[] = "\nsampleRate[%X]: %d, cur_max_freq = %d\n";
AT(.com_text.fft_dbg_str)
const char dbg_str_energy[] = "energy = %d\n\n";
//固定计算128个点的FFT,该输入buf大小为 s32 buf[128], 每次传入128个单声道采样点,计算完成后,一共有64个频率点的幅值信息,存放到buf[0~63]中.可以从该buf中取用
static s32 fft_buf[128];  //lib_fft128库中计算FFT使用到的BUF
AT(.com_text.fft_test)
void dac_fft_calc_test(void)  //每隔一段时间调用dac_fft_calc_test,可以通过打印查看相关FFT信息
{
    int i;
    s16* pdac = (s16*)dac_obuf;
    //一次从dac_obuf中取128 samples进行fft计算,计算前需要把dac_obuf中的双声道数据合并成单声道数据
    for (i = 0; i < 128; i++) {
        fft_buf[i] = pdac[2*i]/2 + pdac[2*i + 1]/2;    //双声道-->单声道
    }
    fft_128_run(fft_buf,18);  //FFT计算后的结果比较大,为了方便计算,第二个参数是把计算结果右移18位(缩小).  第二个参数(取值范围0~32)根据实际需要去做缩小.
    //打印查看FFT结果
    for(i = 0; i < 64; i++) {
        printf(dbg_str_num,fft_buf[i]);
    }
    //如果播放正弦波测试,可以在fft_buf结果中找到最大能量的点,根据当前数据采样率计算得到正弦波频率
    int spr_idx = (DACDIGCON0&(0x0F<<2))>>2;
    u32 fft_128_freq_get(s32 *freq_buf, u32 sample_rate);
    u32 energy_max_freq = fft_128_freq_get(fft_buf,tbl_samplerate[spr_idx]);   //查找能量最大段的FFT频率
    printf(dbg_str_freqinfo,spr_idx, tbl_samplerate[spr_idx],energy_max_freq);
    //128个点的fft, 经过fft_128_run后可以得到64个有效频率成份的幅度, 如当前音乐采样率为44.1K,根据采样定律,最高只能采到其一半的频率信息
    //则fft_buf[i] 处对应的频率为 i*(44100/2/64),手机上播放1K正弦波得到的打印如下, 每个频率间隔为44100/2/64 = 344.5HZ.  播放1K正玄波则刚好在i = 3时有最大幅度值(7)
    //0 0 1 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    //sampleRate[1]: 44100, cur_max_freq = 1033
    //做能量脉动灯时,可以选需要的频率成份的能量进行叠加,效果可能更好.
    u32 energy = 0;
    for (i = 0; i < 32; i++) {      //i max is 63  //示例:这里只选取32*344.5 = 11024HZ 以下的音乐能量进行叠加
        energy += fft_buf[i];
    }
    printf(dbg_str_energy,energy);   //实际计算能量时,需要把fft_128_run的第二个参数调小些.
}
#endif
extern void fft_128_run(s32 *buf, u32 r_shift);
extern u32 fft_128_freq_get(s32 *freq_buf, u32 sample_rate);

s32 fft_buf[128] AT(.fft.buf);
s32 fft_tmp[10] AT(.fft.buf);
u8 high_fre_index;
u8 high_fre_cnt;

u8 low_fre_index;
u8 low_fre_cnt;
u8 password_index;
u8 decryption_success;
u8 wait_end;
u8 project_num;
AT(.com_text.fft_dbg_str)
const char dbg_str_num[] = "%d  ";
const u8 index_num[]={11,12,14,17,20,22,24,26};
const u8 unlock_password_num[MAX_PASSWORK_NUM]={4,5,5,6,3,3,8,7,7,9,2,2};
const u8 lock_password_num[MAX_PASSWORK_NUM]={2,2,9,7,7,8,3,3,6,5,5,4};
u8 password_num[MAX_PASSWORK_NUM]AT(.fft.buf);
const u8 key_num[4][3]=
{
	{1,2,3},
	{4,5,6},
	{7,8,9},
	{10,0,11},	
};
AT(.com.func.speaker)
u8 check_highfre_energy_index(s32 *fft_data,u8 length) 
{
	s32 data_0;
	u8 i,index;
	data_0=fft_data[0];
	index=0;
	for(i=1;i<length;i++)
	{
		if(data_0<fft_data[i])
		{
			data_0=fft_data[i];
			index=i;
		}
	}
	if(data_0<5)
	{
		return 0xff;
	}
	return index;
}
AT(.com.func.speaker)
u8 check_lowfre_energy_index(s32 *fft_data,u8 length) 
{
	s32 data_0;
	u8 i,index;
	data_0=fft_data[0];
	index=0;
	for(i=1;i<length;i++)
	{
		if(data_0<fft_data[i])
		{
			data_0=fft_data[i];
			index=i;
		}
	}
	if(data_0<2)
	{
		return 0xff;
	}
	return index;
}
AT(.com.func.speaker)
void dac_fft_calc_test(u8 *ptr)
{
	s16 *adc_pcm=(s16*)ptr;
	u16 i;
	//int spr_idx = (DACDIGCON0&(0x0F<<2))>>2;
	u8 high_index,low_index,cur_key_num;
	for(i=0;i<128;i++)
	{
		fft_buf[i]=adc_pcm[i];
	}
	fft_128_run(fft_buf,10);
	
	//打印查看FFT结果
	for(i = 0; i < 8; i++) 
	 {	 	
	 	fft_tmp[i]=fft_buf[index_num[i]];
	 }
	#if 0
	if(fft_buf[index_num[4]]>50)
	{
		printf("start:\n");
		 for(i = 0; i < 8; i++) 
		 {		 	
        	printf(dbg_str_num,fft_buf[index_num[i]]);
    	}
		printf("\n end:\n");
	}
	#endif
	high_index=check_highfre_energy_index(&fft_tmp[4],4);
	if(high_index>3)
	{
		high_fre_cnt=0;
		low_fre_cnt=0;
		wait_end=0;
		return;
	}
	if(high_fre_index!=high_index)
	{
		high_fre_index=high_index;
		high_fre_cnt=0;
	}
	else
	{
		high_fre_cnt++;
	}
	low_index=check_lowfre_energy_index(&fft_tmp[0],4);
	if(low_index>3)
	{
		high_fre_cnt=0;
		low_fre_cnt=0;
		wait_end=0;
		return;
	}
	if(low_fre_index!=low_index)
	{
		#if 0
		if(low_fre_index==0&&high_fre_cnt!=0)
		{
			for(i = 0; i < 8; i++) 
			{		 	
	        	printf(dbg_str_num,fft_buf[index_num[i]]);
	    	}
			printf("\n end:\n");
			if(fft_tmp[0]<fft_tmp[1]||fft_tmp[0]<fft_tmp[2])
			{
				low_fre_cnt=0;
			}
			else
			{
				low_fre_cnt++;
				
			}
		}
		else
		#endif
		{
			low_fre_index=low_index;
		}
	}
	else
	{
		low_fre_cnt++;
	}
	
	//printf("start  H:%d->L:%d\n",high_fre_cnt,low_fre_cnt);
	#if 0
	for(i = 0; i < 8; i++) 
	 {
    	printf(dbg_str_num,fft_buf[index_num[i]]);
	}
	#endif
	//printf("\n\n");
	if(high_fre_cnt>=5&&low_fre_cnt>=5&&wait_end==0)
	{
		printf("H index :%d->L index :%d\n",high_fre_index,low_fre_index);
		cur_key_num=key_num[low_fre_index][high_fre_index];
		printf("key num:%d->index:%d\n",cur_key_num,password_index);
		exit_cnt=0;
		if(password_num[password_index]==cur_key_num)
		{
			password_index++;
			
			if(password_index>=MAX_PASSWORK_NUM)
			{
				printf("passwork is ok!!!\n");
				decryption_success=1;
			}
			else
			{
				wait_end=1;
			}
		}
		else
		{
			printf("key num err:%d->index:%d\n",cur_key_num,password_index);
			msg_enqueue(EVT_PASSWORD_ERR);
			password_index=0;
			wait_end=0;
			wait_tts_finish=1;
		}
		high_fre_index=0xff;
		low_fre_index=0xff;
		high_fre_cnt=0;
		low_fre_cnt=0;
	}

}
AT(.com.func.speaker)
void speaker_sdadc_process(u8 *ptr, u32 samples, int ch_mode)
{
	#if 1
	if(wait_tts_finish)
	{
		return;
	}
	dac_fft_calc_test(ptr);
	#else
	s16 *adc_pcm=(s16*)ptr;
	u16 i;
	int spr_idx = (DACDIGCON0&(0x0F<<2))>>2;
	for(i=0;i<128;i++)
	{
		fft_buf[i]=adc_pcm[i];
	}
	fft_128_run(fft_buf,10);
	printf("start 00:%d\n",spr_idx);
	//打印查看FFT结果
	#if 1
	if(fft_buf[index_num[0]]>6)
	{
		printf("start:%d\n",spr_idx);
		 for(i = 0; i < 8; i++) 
		 {		 	
        	printf(dbg_str_num,fft_buf[index_num[i]]);
    	}
		printf("\n end:\n");
	}
   
	#endif
	//
	#endif
#if MIC_REC_EN
    if (f_spk.rec_en) {
        puts_rec_obuf(ptr, (u16)(samples << (1 + ch_mode)));
    }
#endif //MIC_REC_EN
#if MIC_EQ_EN
    sdadc_pcm_peri_eq(ptr,samples);
#endif // MIC_EQ_EN
    sdadc_pcm_2_dac(ptr, samples, ch_mode);
}

AT(.text.func.speaker)
void func_speaker_process(void)
{
    func_process();
}
AT(.text.func.speaker)
u16 exit_speaker_check(void)
{
	exit_cnt++;
	printf("time out cnt:%d\n",exit_cnt);
	if(exit_cnt>=MAX_EXIT_CNT)
	{
		//exit_cnt=0;
		func_cb.sta =func_cb.bak_sta;
	}
	return 0;
}
void passwork_param_init(void)
{
	project_num=param_spiflash_project_num_read();
	if(project_num==1)
	{
		memcpy(password_num,lock_password_num,MAX_PASSWORK_NUM);
	}
	else
	{
		memcpy(password_num,unlock_password_num,MAX_PASSWORK_NUM);
	}
	high_fre_index=0xff;
	low_fre_index=0xff;
	high_fre_cnt=0;
	low_fre_cnt=0;
	password_index=0;
	decryption_success=0;
	wait_tts_finish=0;
	exit_cnt=0;
}
void passwork_func_exit(void)
{
	if(decryption_success)
	{
		AMPLIFIER_SEL_D();
		if(!project_num)
		{
			project_num=1;
			param_spiflash_project_num_write(1);
			mp3_res_play(RES_BUF_EN_LETSDOIT_MP3, RES_LEN_EN_LETSDOIT_MP3);
		}
		else
		{
			project_num=0;
			param_spiflash_project_num_write(0);
			mp3_res_play(RES_BUF_EN_SONGLOCK_MP3, RES_LEN_EN_SONGLOCK_MP3);
		}
		
	}
	else
	{
		printf("time out cnt 11:%d\n",exit_cnt);
		
		if(exit_cnt>=MAX_EXIT_CNT)
		{
			AMPLIFIER_SEL_D();
			if(!project_num)
			{
				mp3_res_play(RES_BUF_EN_UNLOCKOUT_MP3, RES_LEN_EN_UNLOCKOUT_MP3);
			}
			else
			{
				mp3_res_play(RES_BUF_EN_LOCKOUT_MP3, RES_LEN_EN_LOCKOUT_MP3);
			}
		}
	}
}
AT(.text.func.speaker)
void passwork_err_msg(void)
{
	func_speaker_stop();
	AMPLIFIER_SEL_D();
	func_speaker_mp3_res_play(RES_BUF_EN_PASSWORDERR_MP3, RES_LEN_EN_PASSWORDERR_MP3);
	#if SYS_KARAOK_EN
	bsp_karaok_exit(AUDIO_PATH_KARAOK);
	#endif
	AMPLIFIER_SEL_EXIT();
	wait_tts_finish=0;
	exit_cnt=0;
	func_speaker_start();
}

static void func_speaker_enter(void)
{
    memset(&f_spk, 0, sizeof(f_spk));
	
	passwork_param_init();
    func_cb.mp3_res_play = func_speaker_mp3_res_play;
    func_cb.set_vol_callback = func_speaker_setvol_callback;

    func_speaker_enter_display();
    led_music_play();
#if WARNING_FUNC_SPEAKER
    mp3_res_play(RES_BUF_SPK_MODE_MP3, RES_LEN_SPK_MODE_MP3);
#endif // WARNING_FUNC_SPEAKER

#if MIC_REC_EN
    mic_rec_init();
#endif // MIC_REC_EN
#if MIC_EQ_EN
    mic_set_eq_by_res(&RES_BUF_EQ_MIC_NORMAL_EQ, &RES_LEN_EQ_MIC_NORMAL_EQ);
#endif
	#if SYS_KARAOK_EN
	bsp_karaok_exit(AUDIO_PATH_KARAOK);
	#endif
	AMPLIFIER_SEL_EXIT();
    func_speaker_start();
}

static void func_speaker_exit(void)
{
#if MIC_REC_EN
    sfunc_record_stop();
#endif // MIC_REC_EN

    func_speaker_exit_display();
    led_idle();
    func_speaker_stop();
	passwork_func_exit();	
	exit_cnt=0;
    func_cb.last = FUNC_SPEAKER;
}

AT(.text.func.speaker)
void func_speaker(void)
{
    printf("%s\n", __func__);
	
    func_speaker_enter();

    while (func_cb.sta == FUNC_SPEAKER) {
        func_speaker_process();
        func_speaker_message(msg_dequeue());
        func_speaker_display();
		if(decryption_success)
		{
			func_cb.sta =func_cb.bak_sta;
			break;
		}

    }
    func_speaker_exit();
	#if SYS_KARAOK_EN
	bsp_karaok_init(AUDIO_PATH_KARAOK, func_cb.sta);
	#endif
	AMPLIFIER_SEL_D();
}

#endif // FUNC_SPEAKER_EN

